package com.example.analysis.service.impl;

import com.example.analysis.dto.CourseScoreDto;
import com.example.analysis.dto.QuestScoreDto;
import com.example.analysis.dto.QuestScoreSupDto;
import com.example.analysis.dto.StudentPlatformScoreDto;
import com.example.analysis.entity.Course;
import com.example.analysis.mapper.CourseDao;
import com.example.analysis.mapper.StudentDao;
import com.example.analysis.service.CourseService;
import com.example.analysis.service.StudentService;
import com.example.analysis.utils.PCAUtils;
import com.example.analysis.utils.Response;
import com.example.analysis.vo.CourseScoreVo;
import com.example.analysis.vo.QuestScoreVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.apache.commons.math3.linear.*;
import org.apache.commons.math3.stat.correlation.Covariance;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;


@Service
public class CourseServiceImpl implements CourseService {
    private static final Logger log = LoggerFactory.getLogger(CourseServiceImpl.class);
    @Resource
    private CourseDao CourseDao;

    @Autowired
    private CourseDao courseDao;

    @Autowired
    private StudentDao studentDao;

    @Override
    public Response<Course> insert(Course aCourse) {
        try {
            CourseDao.insert(aCourse);
            return new Response<>(true, "Insert success", null);
        } catch (Exception e) {
            return new Response<>(false, "Insert failed: " + e.getMessage(), null);
        }
    }

    @Override
    public Response<Course> getById(String CourseId) {
        Course aCourse = CourseDao.selectByPrimaryKey(CourseId);
        if (aCourse != null) {
            return new Response<>(true, "Success", aCourse);
        } else {
            return new Response<>(false, "Administration not found", null);
        }
    }

    @Override
    public Response<Course> getByName(String CourseName) {
        Course aCourse = CourseDao.selectByName(CourseName);
        if (aCourse != null) {
            return new Response<>(true, "Success", aCourse);
        } else {
            return new Response<>(false, "Administration not found", null);
        }
    }

    @Override
    public Response<List<Course>> getAll() {
        List<Course> courseList = courseDao.getAll();

        if (!courseList.isEmpty()) {
            return new Response<>(true, "Success", courseList);
        } else {
            return new Response<>(false, "Administration not found", null);
        }
    }

    @Override
    public Response<List<Course>> getCourseData(String classId) {
        List<Course> courseList = courseDao.getCourseData(classId);

        if (!courseList.isEmpty()) {
            return new Response<>(true, "Success", courseList);
        } else {
            return new Response<>(false, "Administration not found", null);
        }
    }

    @Override
    public Response<QuestScoreVo> getQuestScore(String subId) {
        List<QuestScoreDto> questScoreDtoList = courseDao.getQuestScore(subId);
        if (questScoreDtoList.isEmpty()) { // 空值判定 为空则未查询到数据集 无需主成分分析
            return new Response<>(false, "Administration not found", null);
        }

        int index = 0;
        double[][] rawData = new double[questScoreDtoList.size() / 6][6];
        for(int i = 0; i < questScoreDtoList.size() / 6; i++) {
            for(int j = 0; j < 6; j++) {
                rawData[i][j] = questScoreDtoList.get(i * 6 + j).getEvaScore();
            }
        }

        // 2. 数据标准化（均值为0，标准差为1）
        RealMatrix data = MatrixUtils.createRealMatrix(rawData);
        RealMatrix scaledData = PCAUtils.standardize(data);
//        System.out.println(scaledData);

        // 3. 计算协方差矩阵
        Covariance covariance = new Covariance(scaledData);
        RealMatrix covarianceMatrix = covariance.getCovarianceMatrix();

        // 4. 计算特征值和特征向量
        EigenDecomposition eigen = new EigenDecomposition(covarianceMatrix);
        double[] eigenvalues = eigen.getRealEigenvalues();
        RealMatrix eigenvectors = eigen.getV();

        // 1. 计算总特征值（总方差）
        double totalEigenvalue = 0;
        for (double eigenvalue : eigenvalues) {
            totalEigenvalue += eigenvalue;
        }

        // 2. 计算每个原始列的总贡献
        double[] columnContributions = new double[6];

        // 遍历每个主成分
        for (int pcIndex = 0; pcIndex < 6; pcIndex++) {
            double eigenvalue = eigenvalues[pcIndex];
            double contributionRate = eigenvalue / totalEigenvalue; // 该主成分的贡献率

            // 遍历每个原始列
            for (int colIndex = 0; colIndex < 6; colIndex++) {
                // 计算该列在当前主成分中的载荷
                double loading = eigenvectors.getEntry(colIndex, pcIndex) * Math.sqrt(eigenvalue);

                // 累积该列的总贡献（载荷平方 × 主成分贡献率）
                columnContributions[colIndex] += Math.pow(loading, 2) * contributionRate;
            }
        }

        // 3. 输出结果
        String[] originalColumnNames = {"1", "2", "3", "4", "5", "6"}; // 示例列名
        System.out.println("各原始列对整体数据的总贡献：");
        for (int i = 0; i < 6; i++) {
            System.out.printf("%s: %.4f%%%n",
                    originalColumnNames[i],
                    columnContributions[i] * 100);
        }

        // 4. 验证：总贡献之和应接近 100%
        double sum = 0;
        for (double c : columnContributions) sum += c;
        System.out.printf("总贡献之和: %.4f%%%n", sum * 100);

        //打印各成分贡献率
        QuestScoreVo questScoreVo = new QuestScoreVo();
        List<Double> doubles = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            doubles.add(columnContributions[i] / sum);
        }
        questScoreVo.setValuesContribution(doubles);

//        // 5. 按特征值排序（降序）
//        List<Integer> indices = IntStream.range(0, eigenvalues.length)
//                .boxed()
//                .sorted((i, j) -> Double.compare(eigenvalues[j], eigenvalues[i]))
//                .collect(Collectors.toList());
//
//        // 6. 选择前2个主成分（示例取前2维）
//        RealMatrix principalComponents = eigenvectors.getSubMatrix(
//                0, eigenvectors.getRowDimension() - 1,
//                indices.get(0), indices.get(1)
//        );
//
//        // 7. 将数据投影到主成分空间
//        RealMatrix transformedData = scaledData.multiply(principalComponents);

        // 8. 输出结果
        System.out.println("特征值（方差贡献）: " + Arrays.toString(eigenvalues));
        System.out.println("特征值（方差贡献）: " + eigenvalues[0]);
        System.out.println("主成分载荷矩阵:\n" + eigenvectors);
//        System.out.println("降维后的数据:\n" + transformedData);
//        System.out.println(principalComponents);

        questScoreVo.setValues(Arrays.stream(eigenvalues).boxed().collect(Collectors.toList()));
//        System.out.println(questScoreVo);

//        System.out.println(questScoreDtoList);
        return new Response<>(true, "Success", questScoreVo);
    }

    @Override
    public Response<QuestScoreVo> getQuestScoreSup(String subId) {
        List<QuestScoreSupDto> questScoreDtoList = courseDao.getQuestScoreSup(subId);
        System.out.println(questScoreDtoList);
        if (questScoreDtoList.isEmpty()) { // 空值判定 为空则未查询到数据集 无需主成分分析
            return new Response<>(false, "Administration not found", null);
        }

        int index = 0;
        double[][] rawData = new double[questScoreDtoList.size() / 6][6];
        for(int i = 0; i < questScoreDtoList.size() / 6; i++) {
            for(int j = 0; j < 6; j++) {
                rawData[i][j] = questScoreDtoList.get(i * 6 + j).getSupervisionScore();
            }
        }

        // 2. 数据标准化（均值为0，标准差为1）
        RealMatrix data = MatrixUtils.createRealMatrix(rawData);
        RealMatrix scaledData = PCAUtils.standardize(data);
//        System.out.println(scaledData);

        // 3. 计算协方差矩阵
        Covariance covariance = new Covariance(scaledData);
        RealMatrix covarianceMatrix = covariance.getCovarianceMatrix();

        // 4. 计算特征值和特征向量
        EigenDecomposition eigen = new EigenDecomposition(covarianceMatrix);
        double[] eigenvalues = eigen.getRealEigenvalues();
        RealMatrix eigenvectors = eigen.getV();

        // 1. 计算总特征值（总方差）
        double totalEigenvalue = 0;
        for (double eigenvalue : eigenvalues) {
            totalEigenvalue += eigenvalue;
        }

        // 2. 计算每个原始列的总贡献
        double[] columnContributions = new double[6];

        // 遍历每个主成分
        for (int pcIndex = 0; pcIndex < 6; pcIndex++) {
            double eigenvalue = eigenvalues[pcIndex];
            double contributionRate = eigenvalue / totalEigenvalue; // 该主成分的贡献率

            // 遍历每个原始列
            for (int colIndex = 0; colIndex < 6; colIndex++) {
                // 计算该列在当前主成分中的载荷
                double loading = eigenvectors.getEntry(colIndex, pcIndex) * Math.sqrt(eigenvalue);

                // 累积该列的总贡献（载荷平方 × 主成分贡献率）
                columnContributions[colIndex] += Math.pow(loading, 2) * contributionRate;
            }
        }

        // 3. 输出结果
        String[] originalColumnNames = {"1", "2", "3", "4", "5", "6"}; // 示例列名
        System.out.println("各原始列对整体数据的总贡献：");
        for (int i = 0; i < 6; i++) {
            System.out.printf("%s: %.4f%%%n",
                    originalColumnNames[i],
                    columnContributions[i] * 100);
        }

        // 4. 验证：总贡献之和应接近 100%
        double sum = 0;
        for (double c : columnContributions) sum += c;
        System.out.printf("总贡献之和: %.4f%%%n", sum * 100);

        //打印各成分贡献率
        QuestScoreVo questScoreVo = new QuestScoreVo();
        List<Double> doubles = new ArrayList<>();
        for (int i = 0; i < 6; i++) {
            doubles.add(columnContributions[i] / sum);
        }
        questScoreVo.setValuesContribution(doubles);
        System.out.println(questScoreVo);

        // 遍历每个特征值及其对应的特征向量
        for (int i = 0; i < eigenvalues.length; i++) {
            double eigenvalue = eigenvalues[i];
            double[] eigenVector = new double[eigenvectors.getRowDimension()];

            // 从矩阵中提取第 i 列（特征向量）
            for (int j = 0; j < eigenVector.length; j++) {
                eigenVector[j] = eigenvectors.getEntry(j, i);
            }

            System.out.println("特征值 " + (i + 1) + ": " + eigenvalue);
            System.out.println("对应的特征向量: " + java.util.Arrays.toString(eigenVector));
            System.out.println();
        }

//        // 5. 按特征值排序（降序）
//        List<Integer> indices = IntStream.range(0, eigenvalues.length)
//                .boxed()
//                .sorted((i, j) -> Double.compare(eigenvalues[j], eigenvalues[i]))
//                .collect(Collectors.toList());

//        // 6. 选择前2个主成分（示例取前2维）
//        RealMatrix principalComponents = eigenvectors.getSubMatrix(
//                0, eigenvectors.getRowDimension() - 1,
//                indices.get(0), indices.get(1)
//        );

//        // 7. 将数据投影到主成分空间
//        RealMatrix transformedData = scaledData.multiply(principalComponents);

//        // 8. 输出结果
        System.out.println("特征值（方差贡献）: " + Arrays.toString(eigenvalues));
//        System.out.println("特征值（方差贡献）: " + eigenvalues[0]);
//        System.out.println("主成分载荷矩阵:\n" + eigenvectors);
//        System.out.println("降维后的数据:\n" + transformedData);
//        System.out.println(principalComponents);
        questScoreVo.setValues(Arrays.stream(eigenvalues).boxed().collect(Collectors.toList()));
//        System.out.println(questScoreVo);

//        System.out.println(questScoreDtoList);
        return new Response<>(true, "Success", questScoreVo);
    }

    // 课程体系成绩数据集
    public List<StudentPlatformScoreDto> getAssociationRulesScoreSetCourses(String classId) {
        List<StudentPlatformScoreDto> studentPlatformScoreDtos = studentDao.getAllStudentsOfOneClass(classId);
        if ( studentPlatformScoreDtos.isEmpty() )
            return null;

        for(int i = 0; i < studentPlatformScoreDtos.size(); i++) {
            studentPlatformScoreDtos.get(i).setDetail1Score((double) 0);
            studentPlatformScoreDtos.get(i).setDetail2Score((double) 0);
            studentPlatformScoreDtos.get(i).setDetail3Score((double) 0);
        }

        for(int i = 0; i < studentPlatformScoreDtos.size(); i++) {
            List<CourseScoreDto> courseScoreData = studentDao.getCourseScoreData(studentPlatformScoreDtos.get(i).getStudentId());

            int index1 = 0;
            int index2 = 0;
            int index3 = 0;

            for (CourseScoreDto courseScoreDto : courseScoreData) {
                switch (courseScoreDto.getPlatform()) {
                    case "通识教育课程": {
                        Double score = studentPlatformScoreDtos.get(i).getDetail1Score() + 0 + courseScoreDto.getSubScore();
                        studentPlatformScoreDtos.get(i).setDetail1Score(score);
                        ++index1;
                    }
                    break;
                    case "学科教育课程": {
                        Double score = studentPlatformScoreDtos.get(i).getDetail2Score() + 0 + courseScoreDto.getSubScore();
                        studentPlatformScoreDtos.get(i).setDetail2Score(score);
                        ++index2;
                    }
                    break;
                    case "专业教育课程": {
                        Double score = studentPlatformScoreDtos.get(i).getDetail3Score() + 0 + courseScoreDto.getSubScore();
                        studentPlatformScoreDtos.get(i).setDetail3Score(score);
                        ++index3;
                    }
                    break;
                }
            }

            if (index1 != 0)
                studentPlatformScoreDtos.get(i).setDetail1Score(studentPlatformScoreDtos.get(i).getDetail1Score() / index1);
            if (index2 != 0)
                studentPlatformScoreDtos.get(i).setDetail2Score(studentPlatformScoreDtos.get(i).getDetail2Score() / index2);
            if (index3 != 0)
                studentPlatformScoreDtos.get(i).setDetail3Score(studentPlatformScoreDtos.get(i).getDetail3Score() / index3);
        }

        System.out.println(studentPlatformScoreDtos);

        return studentPlatformScoreDtos;
    }

    @Override
    public Response<QuestScoreVo> getQuestScoreCourse(String classId) {
        List<StudentPlatformScoreDto> studentPlatformScoreDtos = getAssociationRulesScoreSetCourses(classId);
        System.out.println(studentPlatformScoreDtos);
        if (studentPlatformScoreDtos.isEmpty())
            return new Response<>(false, "Administration not found", null);

        double[][] rawData = new double[studentPlatformScoreDtos.size()][3];
        int index = 0;
        for(int i = 0; i < studentPlatformScoreDtos.size(); i++) {
            if(studentPlatformScoreDtos.get(i).getDetail1Score() == 0.0 || studentPlatformScoreDtos.get(i).getDetail2Score() == 0.0 || studentPlatformScoreDtos.get(i).getDetail3Score() == 0.0)
                continue;
            rawData[index][0] = studentPlatformScoreDtos.get(i).getDetail1Score();
            rawData[index][1] = studentPlatformScoreDtos.get(i).getDetail2Score();
            rawData[index][2] = studentPlatformScoreDtos.get(i).getDetail3Score();
            ++index;
        }

        // 2. 数据标准化（均值为0，标准差为1）
        RealMatrix data = MatrixUtils.createRealMatrix(rawData);
        RealMatrix scaledData = PCAUtils.standardize(data);
//        System.out.println(scaledData);

        // 3. 计算协方差矩阵
        Covariance covariance = new Covariance(scaledData);
        RealMatrix covarianceMatrix = covariance.getCovarianceMatrix();

        // 4. 计算特征值和特征向量
        EigenDecomposition eigen = new EigenDecomposition(covarianceMatrix);
        double[] eigenvalues = eigen.getRealEigenvalues();
        RealMatrix eigenvectors = eigen.getV();

        // 1. 计算总特征值（总方差）
        double totalEigenvalue = 0;
        for (double eigenvalue : eigenvalues) {
            totalEigenvalue += eigenvalue;
        }

        // 2. 计算每个原始列的总贡献
        double[] columnContributions = new double[3];

        // 遍历每个主成分
        for (int pcIndex = 0; pcIndex < 3; pcIndex++) {
            double eigenvalue = eigenvalues[pcIndex];
            double contributionRate = eigenvalue / totalEigenvalue; // 该主成分的贡献率

            // 遍历每个原始列
            for (int colIndex = 0; colIndex < 3; colIndex++) {
                // 计算该列在当前主成分中的载荷
                double loading = eigenvectors.getEntry(colIndex, pcIndex) * Math.sqrt(eigenvalue);

                // 累积该列的总贡献（载荷平方 × 主成分贡献率）
                columnContributions[colIndex] += Math.pow(loading, 2) * contributionRate;
            }
        }

        // 3. 输出结果
        String[] originalColumnNames = {"1", "2", "3"}; // 示例列名
        System.out.println("各原始列对整体数据的总贡献：");
        for (int i = 0; i < 3; i++) {
            System.out.printf("%s: %.4f%%%n",
                    originalColumnNames[i],
                    columnContributions[i] * 100);
        }

        // 4. 验证：总贡献之和应接近 100%
        double sum = 0;
        for (double c : columnContributions) sum += c;
        System.out.printf("总贡献之和: %.4f%%%n", sum * 100);

        // 遍历每个特征值及其对应的特征向量
        for (int i = 0; i < eigenvalues.length; i++) {
            double eigenvalue = eigenvalues[i];
            double[] eigenVector = new double[eigenvectors.getRowDimension()];

            // 从矩阵中提取第 i 列（特征向量）
            for (int j = 0; j < eigenVector.length; j++) {
                eigenVector[j] = eigenvectors.getEntry(j, i);
            }

            System.out.println("特征值 " + (i + 1) + ": " + eigenvalue);
            System.out.println("对应的特征向量: " + java.util.Arrays.toString(eigenVector));
            System.out.println();
        }

//        // 5. 按特征值排序（降序）
//        List<Integer> indices = IntStream.range(0, eigenvalues.length)
//                .boxed()
//                .sorted((i, j) -> Double.compare(eigenvalues[j], eigenvalues[i]))
//                .collect(Collectors.toList());

//        // 6. 选择前2个主成分（示例取前2维）
//        RealMatrix principalComponents = eigenvectors.getSubMatrix(
//                0, eigenvectors.getRowDimension() - 1,
//                indices.get(0), indices.get(1)
//        );

//        // 7. 将数据投影到主成分空间
//        RealMatrix transformedData = scaledData.multiply(principalComponents);

//        // 8. 输出结果
        System.out.println("特征值（方差贡献）: " + Arrays.toString(eigenvalues));
//        System.out.println("特征值（方差贡献）: " + eigenvalues[0]);
//        System.out.println("主成分载荷矩阵:\n" + eigenvectors);
//        System.out.println("降维后的数据:\n" + transformedData);
//        System.out.println(principalComponents);
        QuestScoreVo questScoreVo = new QuestScoreVo();
        questScoreVo.setValues(Arrays.stream(eigenvalues).boxed().collect(Collectors.toList()));
//        System.out.println(questScoreVo);

//        System.out.println(questScoreDtoList);
        return new Response<>(true, "Success", questScoreVo);
    }
}
